<template>
  <div class="app-container">
    <el-container>
      <el-header class="header">
        <h1>菜单接口合并工具</h1>
        <div class="upload-section">
          <el-upload
            class="upload-btn"
            action=""
            :auto-upload="false"
            :on-change="handleMenuUpload"
            :limit="1"
            accept=".json"
            :show-file-list="false"
          >
            <el-button type="primary">导入菜单文件</el-button>
          </el-upload>
          <el-upload
            class="upload-btn"
            action=""
            :auto-upload="false"
            :on-change="handleApiUpload"
            :multiple="true"
            accept=".json"
            :show-file-list="true"
          >
            <el-button type="success">导入接口文件</el-button>
          </el-upload>
          <el-button type="info" @click="exportResult" :disabled="!hasData">导出结果</el-button>
          <el-button type="warning" @click="showCertificatePage = true">证书生成</el-button>
        </div>
      </el-header>
      
      <el-container>
        <el-aside class="aside" width="400px">
          <div class="section-title">菜单树结构</div>
          <!-- 使用div容器包裹菜单树，添加自定义拖拽区域 -->
          <div class="menu-tree-container">
            <el-tree
              v-loading="loading"
              class="menu-tree"
              :data="processedMenus"
              :props="menuProps"
              node-key="id"
              :expand-on-click-node="false"
              @node-click="handleNodeClick"
            >
              <template #default="{ node, data }">
                <div 
                  class="tree-node"
                  @dragover.prevent
                  @drop="(e) => handleDropToMenu(e, data)"
                >
                  <span>{{ node.label }}</span>
                  <el-tag v-if="data.apis && data.apis.length > 0" size="small" type="success" class="api-count">
                    {{ data.apis.length }}个接口
                  </el-tag>
                </div>
              </template>
            </el-tree>
          </div>
        </el-aside>
        
        <el-main class="main">
          <div class="api-tabs">
            <el-tabs v-model="activeTab" type="border-card">
              <el-tab-pane label="所有接口" name="all">
                <div class="api-list">
                  <div class="section-title">接口列表</div>
                  <div class="search-section">
                    <el-input
                      v-model="searchKeyword"
                      placeholder="搜索接口路径或描述"
                      prefix-icon="Search"
                      clearable
                      size="large"
                    />
                  </div>
                  <draggable
                    v-loading="apiLoading"
                    class="draggable-list"
                    :list="filteredApiList"
                    item-key="path"
                    group="api-items"
                    :sort="false"
                  >
                    <template #item="{ element }">
                    <div 
                      class="api-item"
                      draggable="true"
                      @dragstart="(e) => handleDragStart(e, element)"
                    >
                      <el-tag :type="getMethodColor(element.method)">{{ element.method }}</el-tag>
                      <span class="api-path">{{ element.path }}</span>
                      <span class="api-summary">{{ element.summary || '无描述' }}</span>
                    </div>
                  </template>
                  </draggable>
                </div>
              </el-tab-pane>
              <el-tab-pane
                v-for="module in apiModules"
                :key="module.name"
                :label="module.name + ' (' + module.apis.length + '个接口)'"
                :name="module.name"
              >
                <div class="module-content">
                  <!-- 模块整体拖拽 -->
                  <draggable
                    class="module-header"
                    :list="[module]"
                    item-key="name"
                    group="api-items"
                    :sort="false"
                  >
                    <template #item="{ element }">
                      <div 
                        class="module-drag-item"
                        draggable="true"
                        @dragstart="(e) => handleDragStart(e, element)"
                      >
                        <el-icon><Rank /></el-icon>
                        <span>拖拽整个 {{ element.name }} 模块</span>
                        <el-tag size="small" type="primary">{{ element.apis.length }}个接口</el-tag>
                      </div>
                    </template>
                  </draggable>
                  
                  <!-- 模块内单个接口拖拽 -->
                  <div class="module-apis-list">
                    <draggable
                      class="draggable-list"
                      :list="module.apis"
                      item-key="path"
                      group="api-items"
                      :sort="false"
                    >
                      <template #item="{ element }">
                        <div 
                          class="api-item"
                          draggable="true"
                          @dragstart="(e) => handleDragStart(e, element)"
                        >
                          <el-tag :type="getMethodColor(element.method)">{{ element.method }}</el-tag>
                          <span class="api-path">{{ element.path }}</span>
                          <span class="api-summary">{{ element.summary || '无描述' }}</span>
                        </div>
                      </template>
                    </draggable>
                  </div>
                </div>
              </el-tab-pane>
              <!-- 证书生成功能页面 -->
              <el-tab-pane label="证书生成" name="certificate">
                <div class="certificate-container">
                  <div class="section-title">证书生成</div>
                  <el-form :model="certificateForm" :rules="certificateRules" ref="certificateFormRef" label-width="120px" class="certificate-form">
                    <el-form-item label="上传文件" prop="file">
                      <el-upload
                        v-model:file-list="certificateForm.fileList"
                        class="certificate-upload"
                        :auto-upload="false"
                        :limit="1"
                        accept=".csr,.pem"
                        :before-upload="handleCertificateFileUpload"
                      >
                        <el-button type="primary">选择文件</el-button>
                        <template #tip>
                          <div class="el-upload__tip">
                            请上传 .csr 或 .pem 格式的文件
                          </div>
                        </template>
                      </el-upload>
                    </el-form-item>
                    
                    <el-form-item label="过期时间" prop="expiryTime">
                      <el-date-picker
                        v-model="certificateForm.expiryTime"
                        type="datetime"
                        placeholder="选择过期时间"
                        style="width: 100%;"
                        format="YYYY-MM-DD HH:mm:ss"
                        value-format="YYYY-MM-DD HH:mm:ss"
                      />
                    </el-form-item>
                    
                    <el-form-item label="组织单位" prop="ou">
                      <el-input
                        v-model="certificateForm.ou"
                        placeholder="请输入组织单位"
                      />
                    </el-form-item>
                    
                    <el-form-item label="状态" prop="state">
                      <el-input
                        v-model="certificateForm.state"
                        placeholder="请输入状态"
                      />
                    </el-form-item>
                    
                    <el-form-item label="模块ID" prop="modulesId">
                      <el-input
                        v-model="certificateForm.modulesId"
                        placeholder="请输入模块ID"
                      />
                    </el-form-item>
                    
                    <el-form-item>
                      <el-button type="primary" @click="generateCertificate" :loading="certificateLoading">生成证书</el-button>
                      <el-button @click="resetCertificateForm">重置</el-button>
                    </el-form-item>
                  </el-form>
                </div>
              </el-tab-pane>
            </el-tabs>
          </div>
        </el-main>
      </el-container>
      
      <el-footer class="footer">
        <el-dialog v-model="selectedNodeDialog" title="已选接口" width="600px">
          <el-card v-if="selectedNodeData" class="selected-node-card">
            <template #header>
              <div class="card-header">
                <span>{{ selectedNodeData.name }} ({{ selectedNodeData.path }})</span>
                <el-button type="danger" size="small" @click="clearApis">清空接口</el-button>
              </div>
            </template>
            <draggable
              class="selected-apis-list"
              v-model="selectedNodeData.apis"
              item-key="index"
              group="selectedApis"
            >
              <template #item="{ element }">
                <div class="selected-api-item">
                  <span>{{ element }}</span>
                  <el-button type="danger" size="small" icon="Delete" circle @click="removeApi(element)"></el-button>
                </div>
              </template>
            </draggable>
          </el-card>
          <template #footer>
            <el-button @click="selectedNodeDialog = false">关闭</el-button>
          </template>
        </el-dialog>
        
        <!-- 证书生成对话框 -->
        <el-dialog 
          v-model="showCertificatePage" 
          title="证书生成" 
          width="800px"
          :before-close="handleCertificateClose"
          fullscreen
        >
          <CertificateGenerator />
          <template #footer>
            <el-button @click="showCertificatePage = false">关闭</el-button>
          </template>
        </el-dialog>
      </el-footer>
    </el-container>
  </div>
</template>

<script>
import draggable from 'vuedraggable'
import { Rank, Delete, Search } from '@element-plus/icons-vue'
import CertificateGenerator from './components/CertificateGenerator.vue'

export default {
  name: 'App',
  components: {
    draggable,
    Rank,
    Delete,
    Search,
    CertificateGenerator
  },
  data() {
        return {
          menus: [],
          processedMenus: [],
          rawApis: [],
          apiList: [],
          loading: false,
          apiLoading: false,
          selectedNodeDialog: false,
          selectedNodeData: null,
          activeTab: 'all', // 默认选中所有接口标签
          searchKeyword: '', // 搜索关键词
          menuProps: {
            children: 'children',
            label: 'name'
          },
          // 证书生成表单数据
          certificateForm: {
            fileList: [],
            expiryTime: '',
            ou: '',
            state: '',
            modulesId: ''
          },
          certificateLoading: false,
          certificateRules: {
            file: [
              { required: true, message: '请选择上传文件', trigger: 'change' }
            ],
            expiryTime: [
              { required: true, message: '请选择过期时间', trigger: 'change' }
            ],
            ou: [
              { required: true, message: '请输入组织单位', trigger: 'blur' }
            ],
            state: [
              { required: true, message: '请输入状态', trigger: 'blur' }
            ],
            modulesId: [
              { required: true, message: '请输入模块ID', trigger: 'blur' }
            ]
          },
            showCertificatePage: false
        }
      },
  computed: {
    hasData() {
      return this.processedMenus.length > 0
    },
    
    // 根据搜索关键词过滤的接口列表
    filteredApiList() {
      if (!this.searchKeyword.trim()) {
        return this.apiList
      }
      
      const keyword = this.searchKeyword.toLowerCase().trim()
      return this.apiList.filter(api => {
        return (
          api.path.toLowerCase().includes(keyword) ||
          (api.summary && api.summary.toLowerCase().includes(keyword)) ||
          (api.method && api.method.toLowerCase().includes(keyword)) ||
          (api.tags && api.tags.some(tag => tag.toLowerCase().includes(keyword)))
        )
      })
    },
    // 按模块分组的接口列表
    apiModules() {
      const moduleMap = {}
      const filteredApis = this.filteredApiList
      
      // 遍历过滤后的接口，按tag分组
      filteredApis.forEach(api => {
        if (api.tags && api.tags.length > 0) {
          api.tags.forEach(tag => {
            if (!moduleMap[tag]) {
              moduleMap[tag] = {
                name: tag,
                apis: []
              }
            }
            moduleMap[tag].apis.push(api)
          })
        } else {
          // 没有tag的接口放入"未分类"模块
          if (!moduleMap['未分类']) {
            moduleMap['未分类'] = {
              name: '未分类',
              apis: []
            }
          }
          moduleMap['未分类'].apis.push(api)
        }
      })
      
      // 转换为数组并按名称排序
      return Object.values(moduleMap).sort((a, b) => {
        if (a.name === '未分类') return 1
        if (b.name === '未分类') return -1
        return a.name.localeCompare(b.name)
      })
    }
  },
  methods: {
      // 拖拽开始时设置数据
      handleDragStart(event, data) {
        event.dataTransfer.effectAllowed = 'copy';
        event.dataTransfer.setData('application/json', JSON.stringify(data));
        event.dataTransfer.setData('text/plain', JSON.stringify(data));
      },
    // 处理菜单文件上传
    handleMenuUpload(file) {
      const reader = new FileReader()
      reader.onload = (e) => {
        try {
          this.loading = true
          const menus = JSON.parse(e.target.result)
          this.menus = menus
          this.processedMenus = this.transformMenus(menus)
          this.$message.success('菜单文件导入成功')
        } catch (error) {
          this.$message.error('菜单文件格式错误')
        } finally {
          this.loading = false
        }
      }
      reader.readAsText(file.raw)
    },
    
    // 处理接口文件上传
    handleApiUpload(file) {
      const reader = new FileReader()
      reader.onload = (e) => {
        try {
          this.apiLoading = true
          const apiData = JSON.parse(e.target.result)
          // 解析OpenAPI格式的接口
          if (apiData.paths) {
            const newApis = this.parseOpenApi(apiData)
            this.rawApis = [...this.rawApis, ...newApis]
            this.apiList = [...this.apiList, ...newApis]
            this.$message.success('接口文件导入成功，新增' + newApis.length + '个接口')
          } else {
            // 处理其他格式的接口文件
            this.$message.error('不支持的接口文件格式')
          }
        } catch (error) {
          this.$message.error('接口文件格式错误')
        } finally {
          this.apiLoading = false
        }
      }
      reader.readAsText(file.raw)
    },
    
    // 转换菜单数据为目标格式
    transformMenus(menus) {
      const transform = (menu) => {
        return {
          id: menu.menuId || menu.id,
          parentId: menu.parentId || 0,
          name: menu.menuName || menu.name,
          path: menu.path,
          apis: [],
          children: menu.children ? menu.children.map(child => transform(child)) : []
        }
      }
      
      return Array.isArray(menus) ? menus.map(menu => transform(menu)) : []
    },
    
    // 解析OpenAPI格式的接口
    parseOpenApi(apiData) {
      const apis = []
      const paths = apiData.paths || {}
      
      Object.keys(paths).forEach(path => {
        const pathItem = paths[path]
        Object.keys(pathItem).forEach(method => {
          if (method !== 'parameters') {
            const operation = pathItem[method]
            apis.push({
              method: method.toUpperCase(),
              path: path,
              summary: operation.summary || '',
              tags: operation.tags || []
            })
          }
        })
      })
      
      return apis
    },
    
    // 获取HTTP方法对应的颜色
    getMethodColor(method) {
      const colors = {
        'GET': 'primary',
        'POST': 'success',
        'PUT': 'warning',
        'DELETE': 'danger',
        'PATCH': 'info',
        'HEAD': 'info',
        'OPTIONS': 'info'
      }
      return colors[method] || 'info'
    },
    
    // 处理拖拽到菜单节点
    handleDropToMenu(event, menuNode) {
      event.preventDefault();
      
      // 获取拖拽的数据
      const draggedData = JSON.parse(event.dataTransfer.getData('application/json') || event.dataTransfer.getData('text/plain'));
      
      if (!draggedData) return;
      
      // 检查是否是整个模块拖过来的
      if (draggedData.name && draggedData.apis) {
        const moduleName = draggedData.name;
        let addedCount = 0;
        
        draggedData.apis.forEach(api => {
          const apiPath = `${api.method} ${api.path}`;
          if (!menuNode.apis.includes(apiPath)) {
            menuNode.apis.push(apiPath);
            addedCount++;
          }
        });
        
        if (addedCount > 0) {
          this.$message.success(`成功添加 ${moduleName} 模块的 ${addedCount} 个接口到菜单`);
        } else {
          this.$message.warning('该模块的接口已全部存在于菜单中');
        }
      }
      // 单个接口拖过来的
      else if (draggedData.method) {
        const apiPath = `${draggedData.method} ${draggedData.path}`;
        if (!menuNode.apis.includes(apiPath)) {
          menuNode.apis.push(apiPath);
          this.$message.success('接口已添加到菜单');
        } else {
          this.$message.warning('接口已存在');
        }
      }
    },
    
    // 处理节点点击
    handleNodeClick(data) {
      this.selectedNodeData = data
      this.selectedNodeDialog = true
    },
    
    // 移除单个接口
    removeApi(apiPath) {
      if (this.selectedNodeData) {
        const index = this.selectedNodeData.apis.indexOf(apiPath)
        if (index > -1) {
          this.selectedNodeData.apis.splice(index, 1)
          this.$message.success('接口已移除')
        }
      }
    },
    
    // 清空所有接口
    clearApis() {
      if (this.selectedNodeData) {
        this.$confirm('确定要清空所有接口吗？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.selectedNodeData.apis = []
          this.$message.success('已清空所有接口')
        }).catch(() => {})
      }
    },
    
    // 导出结果
    exportResult() {
      const result = JSON.stringify(this.processedMenus, null, 2)
      const blob = new Blob([result], { type: 'application/json' })
      const url = URL.createObjectURL(blob)
      const link = document.createElement('a')
      link.href = url
      link.download = 'license_modules.json'
      link.click()
      URL.revokeObjectURL(url)
      this.$message.success('导出成功')
    },
    
    // 处理证书生成对话框关闭
    handleCertificateClose() {
      this.showCertificatePage = false
    }
  }
}
</script>

<style>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;
}

.app-container {
  height: 100vh;
  overflow: hidden;
}

.header {
  background-color: #1f2937;
  color: white;
  padding: 0 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 60px;
}

.header h1 {
  font-size: 20px;
  font-weight: 500;
}

.upload-section {
  display: flex;
  gap: 10px;
}

.upload-btn .el-upload__text {
  color: white;
}

.aside {
  background-color: #f5f7fa;
  border-right: 1px solid #e4e7ed;
  overflow-y: auto;
  height: calc(100vh - 60px);
}

.main {
  padding: 20px;
  overflow-y: auto;
  height: calc(100vh - 60px);
}

.section-title {
  font-size: 16px;
  font-weight: 500;
  margin-bottom: 15px;
  color: #303133;
  padding: 15px 20px 0;
}

.search-section {
  padding: 0 20px 15px;
}

.menu-tree-container {
  height: 100%;
}

.menu-tree {
  padding: 20px;
  height: 100%;
}

.tree-node {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding: 4px 0;
}

.tree-node:hover {
  background-color: #f0f9eb;
  border-radius: 4px;
}

.tree-node {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.api-count {
  margin-left: 10px;
}

.api-tabs {
  height: 100%;
  display: flex;
  flex-direction: column;
}

/* 证书生成页面样式 */
.certificate-container {
  padding: 20px;
  height: 100%;
  overflow-y: auto;
}

.certificate-form {
  max-width: 800px;
  background-color: #ffffff;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.certificate-upload {
  display: block;
}

.el-form-item {
  margin-bottom: 24px;
}

.el-tabs {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.el-tabs__content {
  flex: 1;
  overflow: hidden;
}

.api-list {
  max-height: 100%;
  overflow-y: auto;
  padding: 10px;
}

.module-content {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 10px;
}

.module-header {
  margin-bottom: 10px;
}

.module-drag-item {
  background-color: #409eff;
  color: white;
  padding: 15px 20px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: grab;
  transition: all 0.3s;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.module-drag-item:active {
  cursor: grabbing;
}

.module-drag-item:hover {
  background-color: #66b1ff;
  transform: translateY(-2px);
  box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.15);
}

.module-apis-list {
  flex: 1;
  overflow-y: auto;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
  background-color: #fafafa;
}

.draggable-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.api-item {
  background-color: #f5f7fa;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 12px 15px;
  cursor: grab;
  display: flex;
  align-items: center;
  gap: 10px;
  transition: all 0.3s;
}

.api-item:active {
  cursor: grabbing;
}

.api-item:hover {
  background-color: #ecf5ff;
  border-color: #d9ecff;
}

.api-path {
  font-weight: 500;
  color: #303133;
  flex: 1;
}

.api-summary {
  color: #606266;
  font-size: 12px;
}

/* 拖拽状态样式 */
.module-drag-item.sortable-chosen,
.api-item.sortable-chosen {
  background-color: #f0f9eb !important;
  border-color: #67c23a !important;
}

.module-drag-item.sortable-drag,
.api-item.sortable-drag {
  opacity: 0.6;
}

.selected-node-card {
  margin-bottom: 0;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.selected-apis-list {
  max-height: 400px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.selected-api-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: #f5f7fa;
  padding: 8px 12px;
  border-radius: 4px;
}

.footer {
  padding: 0;
}
</style>
